#include "app_device.h"
#include "thirdparty/log.c/log.h"
#include "app_task.h"
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/time.h>

#define BUFFER_LEN 16384

static long app_device_getTimestamp()
{
    long result;
    struct timeval time;
    if (gettimeofday(&time, NULL) < 0)
    {
        log_warn("Device: gettimeofday failed!");
        return 0;
    }
    result = time.tv_sec * 1000 + time.tv_usec / 1000;
    return result;
}

/**
 * @brief 设备后台逻辑
 *
 * @param argv 设备指针
 * @return void* 返回值永远为NULL
 */
static void *app_device_backgroundThread(void *argv)
{
    unsigned char buf[1024];
    Device *device = argv;
    Task task;
    log_trace("Device %s: background thread try to read", device->filename);
    while (1)
    {
        // 不断读取设备fd
        int len = read(device->fd, buf, 1024);
        log_trace("Device %s: background thread read len %d", device->filename, len);
        // 读到数据后，后处理并写到缓存
        if (device->vptr->post_recv)
        {
            device->vptr->post_recv(device, buf, &len);
        }
        if (len > 0)
        {
            // 需要处理
            if (app_buffer_write(device->read_buffer, buf, len) < 0)
            {
                log_warn("Device %s: background thread write buffer overflow", device->filename);
            }
            log_trace("Device %s: background thread write to buffer success", device->filename);
            task.callback = device->vptr->recv_task;
            task.argv = device;
            app_task_registerTask(&task);
        }
    }
    return NULL;
}

static void app_device_defaultSendTask(void *argv)
{
    // 从写缓存中读取消息
    unsigned char buf[256];
    Device *device = argv;

    if (app_buffer_read(device->write_buffer, buf, 2) <= 0)
    {
        log_warn("Device %s: send task read buffer fail", device->filename);
        return;
    }
    app_buffer_read(device->write_buffer, buf + 2, buf[0] + buf[1]);
    int len = buf[0] + buf[1] + 2;
    log_trace("Device %s: send task read success", device->filename);

    // 发送前处理
    if (device->vptr->pre_send)
    {
        device->vptr->pre_send(device, buf, &len);
    }
    // 发送到设备
    while (app_device_getTimestamp() - device->last_write_ts < device->write_interval)
    {
        usleep(1000);
    }

    if (len > 0)
    {
        log_trace("Device %s: write to fd", device->filename);
        if (write(device->fd, buf, len) < 0)
        {
            log_warn("Device %s: write to fd fail", device->filename);
        }
        device->last_write_ts = app_device_getTimestamp();
    }
}

static void app_device_defaultRecvTask(void *argv)
{
    // 从缓存中读取message并调用回调函数
    unsigned char buf[256];
    Device *device = argv;
    if (app_buffer_read(device->read_buffer, buf, 2) <= 0)
    {
        log_warn("Device %s: recv task read buffer fail", device->filename);
        return;
    }
    app_buffer_read(device->read_buffer, buf + 2, buf[0] + buf[1]);
    log_trace("Device %s: recv task read success", device->filename);

    device->vptr->recv_callback(device, buf, buf[0] + buf[1] + 2);
}

int app_device_init(Device *device, char *filename)
{
    log_info("Device %s begin to initialize...", filename);
    // 申请内存
    int filename_len = strlen(filename) + 1;
    device->filename = malloc(filename_len);
    if (!device->filename)
    {
        goto INIT_FAIL;
    }
    log_debug("Device filename mem alloced!");

    device->vptr = malloc(sizeof(VTable));
    if (!device->vptr)
    {
        goto FILENAME_FAIL;
    }
    log_debug("Device vptr mem alloced!");

    device->read_buffer = malloc(sizeof(Buffer));
    if (!device->read_buffer)
    {
        goto VPTR_FAIL;
    }
    log_debug("Device read buffer mem alloced!");

    device->write_buffer = malloc(sizeof(Buffer));
    if (!device->write_buffer)
    {
        goto READ_BUFFER_PTR_FAIL;
    }
    log_debug("Device write buffer mem alloced!");

    // 初始化
    // 拷贝文件名
    memcpy(device->filename, filename, filename_len);
    // 初始化类型
    device->device_type = GENERAL;
    // 连接类型
    device->connection_type = OTHER;
    // 读写缓存初始化
    if (app_buffer_init(device->read_buffer, BUFFER_LEN) < 0)
    {
        goto WRITE_BUFFER_PTR_FAIL;
    }
    log_debug("Device read buffer initialized!");
    if (app_buffer_init(device->write_buffer, BUFFER_LEN) < 0)
    {
        goto READ_BUFFER_FAIL;
    }
    log_debug("Device write buffer initialized!");
    // 文件描述符
    device->fd = open(filename, O_RDWR | O_NOCTTY);
    if (device->fd < 0)
    {
        goto WRITE_BUFFER_FAIL;
    }
    log_debug("Device fd opened!");

    device->background_t = 0;
    device->last_write_ts = 0;
    device->write_interval = 0;

    // 虚表初始化
    // TODO 需要写一个后台线程逻辑
    device->vptr->background_thread = app_device_backgroundThread;

    // 数据接收和发送的前后处理函数，由子类实现
    device->vptr->post_recv = NULL;
    device->vptr->pre_send = NULL;

    // TODO 数据接收后和发送后的任务逻辑需要实现
    device->vptr->recv_task = app_device_defaultRecvTask;
    device->vptr->send_task = app_device_defaultSendTask;

    // 回调函数注册由上级调用实现
    device->vptr->recv_callback = NULL;

    log_info("Device %s initialize succeeded!", filename);
    return 0;
WRITE_BUFFER_FAIL:
    app_buffer_free(device->write_buffer);
READ_BUFFER_FAIL:
    app_buffer_free(device->read_buffer);
WRITE_BUFFER_PTR_FAIL:
    free(device->write_buffer);
READ_BUFFER_PTR_FAIL:
    free(device->read_buffer);
VPTR_FAIL:
    free(device->vptr);
FILENAME_FAIL:
    free(device->filename);
INIT_FAIL:
    log_error("Not enough memory for device %s", filename);
    return -1;
}

int app_device_start(Device *device)
{
    if (device->background_t)
    {
        log_warn("Device %s already started", device->filename);
        return -1;
    }
    if (pthread_create(&device->background_t, NULL, device->vptr->background_thread, device) < 0)
    {
        log_error("Device %s start failed", device->filename);
        return -1;
    }
    log_info("Device %s started", device->filename);
    return 0;
}

int app_device_write(Device *device, void *ptr, int len)
{
    Task task;
    // 将二进制消息写到缓存
    if (app_buffer_write(device->write_buffer, ptr, len) < 0)
    {
        log_warn("Device %s write buffer overflowed!", device->filename);
        return -1;
    }
    // 注册一个send_task
    task.callback = device->vptr->send_task;
    task.argv = device;
    app_task_registerTask(&task);
    return 0;
}

void app_device_registerRecvCallback(Device *device, int (*recv_callback)(Device *, void *, int))
{
    device->vptr->recv_callback = recv_callback;
}

int app_device_stop(Device *device)
{
    if (!device->background_t)
    {
        log_warn("Device %s not started!", device->filename);
        return -1;
    }
    if (pthread_cancel(device->background_t) < 0)
    {
        log_error("Device %s background thread stop failed!", device->filename);
        return -1;
    }
    if (pthread_join(device->background_t, NULL) < 0)
    {
        log_error("Device %s background thread join failed!", device->filename);
        return -1;
    }
    device->background_t = 0;
    log_info("Device %s stopped", device->filename);
    return 0;
}

void app_device_close(Device *device)
{
    log_info("Device %s closing", device->filename);
    if (device->write_buffer)
    {
        app_buffer_free(device->write_buffer);
        free(device->write_buffer);
        device->write_buffer = NULL;
    }
    if (device->read_buffer)
    {
        app_buffer_free(device->read_buffer);
        free(device->read_buffer);
        device->read_buffer = NULL;
    }
    if (device->vptr)
    {
        free(device->vptr);
        device->vptr = NULL;
    }
    if (device->filename)
    {
        free(device->filename);
        device->filename = NULL;
    }
}
